package com.nowcoder.community.util;

import jakarta.annotation.PostConstruct;
import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;

@Component
public class SensitiveFilter {

    private final static Logger logger = LoggerFactory.getLogger(SensitiveFilter.class);

    // 用于替换敏感词的串
    private final String REPLACE_STR = "***";

    private TrieNode trieRoot;

    public SensitiveFilter() {}

    private class TrieNode {

        // 标明该节点所存储的字符是不是一个敏感词汇的结尾字符
        // 标记着搜索终点
        private boolean isKeyWordEnd = false;

        private HashMap<Character, TrieNode> childNodes;

        private Character character;

        public TrieNode(Character c) {
            this.character = c;
            this.childNodes = new HashMap<>();
        }

        public boolean isKeyWordEnd() {
            return isKeyWordEnd;
        }

        public void setKeyWordEnd(boolean keyWordEnd) {
            isKeyWordEnd = keyWordEnd;
        }

        public TrieNode addNode(Character c) {
            if(!childNodes.containsKey(c)) {
                childNodes.put(c, new TrieNode(c));
            }
            return childNodes.get(c);
        }

        public TrieNode getNode(Character c) {
            return childNodes.containsKey(c) ? childNodes.get(c) : null;
        }
    }

    // 添加敏感词到前缀树中
    private void addKeyword(String keyword) {
        TrieNode cur = trieRoot;
        int len = keyword.length();
        for(int i = 0; i < len; i++) {
            char c = keyword.charAt(i);
            if(cur != null) {
                // TrieNode node = new TrieNode(c);
                // cur.addNode(c, node);
                cur = cur.addNode(c);
                if(i == len - 1) {
                    cur.setKeyWordEnd(true);
                }
            }
            else {
                logger.error("向前缀树中添加敏感词失败");
                throw new RuntimeException("Add Keyword Error!");
            }
        }
    }

    // 初始化前缀树
    // 在Bean被初始化的时候调用
    @PostConstruct
    public void init() throws IOException {
        this.trieRoot = new TrieNode(' ');
        try (
                InputStream is = this.getClass().getClassLoader().getResourceAsStream("files/sensitive-words.txt");
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            )
        {
            String keyword;
            while((keyword = reader.readLine()) != null) {
                this.addKeyword(keyword);
            }
        } catch (IOException e) {
            logger.error("加载敏感词文件失败!" + e.getMessage());
        }
    }

    // 判断是否是奇奇怪怪的符号
    private boolean isSymbol(char c) {
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0X2E80 || c > 0X9FFF);
    }

    /**
     * 根据创建好的前缀树
     * 过滤敏感词
     *
     * @param text
     * @return
     */
    public String filter(String text) {
        if(StringUtils.isBlank(text)) {
            return null;
        }
        int left = 0, right = 0, len = text.length();
        TrieNode move = trieRoot;
        StringBuilder str = new StringBuilder();
        while(left < len) {
            char c = text.charAt(left);
            if(isSymbol(c)) {
                str.append(c);
                left++;
            }
            else {
                right = left;
                while(right < len && move != null && !move.isKeyWordEnd()) {
                    char d = text.charAt(right);
                    if(isSymbol(d)) {
                        right++;
                    }
                    else {
                        TrieNode node = move.getNode(d);
                        if(node == null) {
                            if(move == trieRoot) {
                                right++;
                            }
                            break;
                        }
                        else {
                            move = node;
                            right++;
                        }
                    }
                }
                // 极特殊情况判断
                // 一般不会发生，避免直接向客户端输出报错信息
                if(move == null) {
                    logger.error("遍历字符串是时, 字典树指针的得到空!");
                    throw new RuntimeException("Pointer move is null!");
                }
                // 不是敏感词
                if(!move.isKeyWordEnd()) {
                    str.append(text.substring(left, right));
                }
                // 是敏感词
                else {
                    str.append(REPLACE_STR);
                }
                left = right;
                move = trieRoot;
            }
        }
        return str.toString();
    }
}
